﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using BlindData.Names;
using System.Diagnostics.Contracts;

namespace BlindData.TestVisualizer
{
	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public partial class MainWindow : Window
	{
		private IGenerator _generator = new RandomGenerator();

		public MainWindow()
		{
			InitializeComponent();

			var testList = new List<TestListItem>(new TestListItem[]
			{
				new TestListItem("Bool Probability", BoolProbability),
				new TestListItem("Name ToString", NameToString)
			});

			tests.ItemsSource = testList;
			tests.DisplayMemberPath = "Name";
			tests.SelectedValuePath = "Test";
		}

		private void RunTests(object sender, RoutedEventArgs e)
		{
			var test = (Func<string>)tests.SelectedValue;
			if (test != null)
			{
				results.Text = test();
			}
		}

		#region BoolProbability

		public string BoolProbability()
		{
			var sb = new StringBuilder();

			RunBoolProbabilityTestSet(sb, new Probability(0));
			RunBoolProbabilityTestSet(sb, new Probability(0.000001));
			RunBoolProbabilityTestSet(sb, new Probability(0.1));
			RunBoolProbabilityTestSet(sb, new Probability(0.5));
			RunBoolProbabilityTestSet(sb, new Probability(0.9));
			RunBoolProbabilityTestSet(sb, new Probability(0.99999));
			RunBoolProbabilityTestSet(sb, new Probability(1));

			return sb.ToString();
		}

		public void RunBoolProbabilityTestSet(StringBuilder sb, Probability probability)
		{
			RunBoolProbabilityTest(sb, 100, probability);
			RunBoolProbabilityTest(sb, 1000, probability);
			RunBoolProbabilityTest(sb, 10000, probability);
			RunBoolProbabilityTest(sb, 100000, probability);
			RunBoolProbabilityTest(sb, 1000000, probability);
			sb.AppendLine();
		}

		public void RunBoolProbabilityTest(StringBuilder sb, int runCount, Probability probability)
		{
			var trueCount = 0;

			for (int i = 0; i < runCount; i++)
			{
				if (_generator.Next<bool>().WithTrueProbability(probability))
				{
					trueCount++;
				}
			}

			sb.AppendLine(
				String.Format(
					"Probability:{1} True Percent:{2}% Run Count:{0}",
					runCount,
					probability.ToDouble(),
					((double)trueCount / (double)runCount) * 100
				));
		}

		#endregion

		#region NameToString

		private string NameToString()
		{
			var sb = new StringBuilder();

			BuildNameTest(sb, "James", null, "Bond");
			BuildNameTest(sb, "Christopher", "Scott", "Bondeson");
			BuildNameTest(sb, "Cher", null, null);
			BuildNameTest(sb, null, null, "Bono");
			BuildNameTest(sb, null, "John", "Doe");
			BuildNameTest(sb, null, null, null);
			BuildNameTest(sb, String.Empty, String.Empty, String.Empty);

			return sb.ToString();
		}

		private void BuildNameTest(StringBuilder sb, string firstName, string middleName, string lastName)
		{
			Name name = null;
			try
			{
				sb.AppendLine(String.Format("Creating Name: First-'{0}' Middle-'{1}' Last-'{2}'", firstName, middleName, lastName));
				name = new Name(firstName, middleName, lastName);
			}
			catch(Exception e)
			{
				sb.AppendLine(String.Format("Failed to create name: {0}", e.Message));
			}

			if (name != null)
			{
				sb.AppendLine(String.Format("ToFirstLast() = '{0}'", name.ToFirstLast()));
				sb.AppendLine(String.Format("ToFirstLastInitial() = '{0}'", name.ToFirstLastInitial()));
				sb.AppendLine(String.Format("ToFirstMiddleInitialLast() = '{0}'", name.ToFirstMiddleInitialLast()));
				sb.AppendLine(String.Format("ToFirstMiddleLast() = '{0}'", name.ToFirstMiddleLast()));
				sb.AppendLine(String.Format("ToInitials() = '{0}'", name.ToInitials()));
				sb.AppendLine(String.Format("ToInitialsWithPeriods() = '{0}'", name.ToInitialsWithPeriods()));
				sb.AppendLine(String.Format("ToLastFirst() = '{0}'", name.ToLastFirst()));
				sb.AppendLine(String.Format("ToLastFirstInitial() = '{0}'", name.ToLastFirstInitial()));
				sb.AppendLine(String.Format("ToString() = '{0}'", name.ToString()));
				sb.AppendLine(String.Format("ToString('**F f m l L**') = '{0}'", name.ToString("**F f m l L**")));
				sb.AppendLine(String.Format("ToString('--FI fi mi li LI--') = '{0}'", name.ToString("--FI fi mi li LI--")));
			}
			sb.AppendLine();
		}

		#endregion
	}

	public class TestListItem
	{
		public string Name { get; private set; }

		public Func<string> Test { get; private set; }

		public TestListItem(string name, Func<string> test)
		{
			Contract.Requires(!String.IsNullOrEmpty(name));
			Contract.Requires(test != null);

			this.Name = name;
			this.Test = test;
		}
	}
}
